package app.controllers.trade;

import app.jobs.asyn.InstantPayJob;
import app.kit.CommonKit;
import app.kit.TypeKit;
import app.models.order.TradeMoney;
import app.models.order.TradeMoneyRecord;
import app.models.product.Product;
import bank.BankService;
import bank.resp.AccountAmountRspDto;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.jfinal.aop.Before;
import com.jfinal.ext.interceptor.POST;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Record;
import goja.Func;
import goja.Logger;
import goja.StringPool;
import goja.kits.base.DateKit;
import goja.lang.Lang;
import goja.mvc.Controller;
import goja.plugins.sqlinxml.SqlKit;
import goja.rapid.datatables.DTCriterias;
import goja.rapid.db.Condition;
import goja.security.shiro.AppUser;
import goja.security.shiro.Securitys;
import goja.tuples.Pair;
import org.joda.time.DateTime;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;

import static app.Const.FIELD_AMOUNT;
import static app.Const.FIELD_STATUS;
import static app.Const.PARAM_DATA;
import static app.models.order.TradeMoney.CANCEL_TYPE;
import static app.models.order.TradeMoney.CONFIRM_STATUS;
import static app.models.order.TradeMoney.DUE_TYPE;
import static app.models.order.TradeMoney.FAIL_TYPE;
import static app.models.order.TradeMoney.OK_STATUS;
import static app.models.order.TradeMoney.PAY_FAIL_TYPE;
import static app.models.order.TradeMoney.RAISED_SUCCESS_TYPE;
import static app.models.order.TradeMoney.SUCCESS_STATUS;
import static app.models.order.TradeMoney.TRANSFER_TYPE;
import static app.models.order.TradeMoney.dao;

/**
 * <p>
 * The url trade/playmoney Controller.
 * </p>
 * 打款操作
 *
 * @author sagyf yang
 * @version 1.0
 * @since JDK 1.6
 */
public class PlaymoneyController extends Controller {

    /**
     * The index route.
     * the url /trade/playmoney
     * the view in index.ftl
     */
    public void index() {
        //        打款类型
        int type = getParaToInt(0, 0);
        int productId = getParaToInt(1, 0);
        if (type <= 0 || productId <= 0) {
            renderNull();
            return;
        }
        String title;
        switch (type) {
            case DUE_TYPE:
                setAttr("product", Product.dao.findByClearing(type, productId));
                title = "产品到期结算清单";

                break;
            case FAIL_TYPE:
                setAttr("product", Product.dao.findByClearing(type, productId));
                title = "募集失败资金返还清单";

                break;
            case TRANSFER_TYPE:
                setAttr("product", Product.dao.findByClearing(type, productId));
                title = "转让资金结算清单";

                break;
            case CANCEL_TYPE:
                setAttr("product", Product.dao.findByClearing(type, productId));
                title = "产品退单资金结算清单";

                break;
            case RAISED_SUCCESS_TYPE:
                setAttr("product", Product.dao.findByClearing(type, productId));
                title = "产品募集到期结算清单";

                break;
            case PAY_FAIL_TYPE:
                title = "交易失败结算清单";
                String day = getPara("day");
                if (Strings.isNullOrEmpty(day)) {
                    renderNull();
                } else {
                    Record record = TradeMoney.dao.statFailByDay(day);
                    setAttr("stat", record);
                }
                setAttr("day", day);
                break;
            default:
                title = "打款清单";

                break;
        }
        setAttr("productId", productId);
        setAttr("title", title);
        setAttr("type", type);
        setAttr("date", DateTime.now().toDate());
    }

    /**
     * 列表数据
     */
    public void dtlist() {
        //打款类型
        int type = getParaToInt(0, 0);
        final DTCriterias criterias = getCriterias();
        if (type == PAY_FAIL_TYPE) {
            String day = getPara("day");
            if (!Strings.isNullOrEmpty(day)) {
                DateTime dayTime = DateKit.parseDashYMDDateTime(day);
                criterias.setParam("o.buy_time", Condition.BETWEEN, new Object[]{dayTime.millisOfDay().withMinimumValue(), dayTime.millisOfDay().withMaximumValue()});
            }
            criterias.setParam("tm.type", type);

        } else {
            int productId = getParaToInt(1, 0);
            if (type <= 0 || productId <= 0) {
                renderEmptyDataTables(criterias);
                return;
            }

            criterias.setParam("tm.type", type);
            criterias.setParam("tm.product", productId);

            String time_q = getPara("time");
            if (!Strings.isNullOrEmpty(time_q)) {
                Pair<DateTime, DateTime> rangeDatetime = CommonKit.rangeDatetime(time_q);
                if (rangeDatetime != null) {
                    criterias.setParam("tm.submit_time", Condition.BETWEEN, new Object[]{rangeDatetime.getValue0(), rangeDatetime.getValue1()});
                }
            }
        }
        renderDataTables(criterias, "trademoney");
    }

    /**
     * 执行编辑操作
     */
    public void edit() {

        TradeMoney tradeMoney = dao.findByUpdate(getParaToInt());
        final int status = tradeMoney.getNumber(FIELD_STATUS).intValue();
        boolean edit = status == SUCCESS_STATUS || status == CONFIRM_STATUS || status == OK_STATUS;
        if (edit) {
            setAttr("error", "该打款信息已经确认或者已打款，无法修改");
        }

        setAttr("t", tradeMoney);
        setAttr("edit", edit);

        render("item.ftl");

    }



    @Before(POST.class)
    public void save() {

        TradeMoney tradeMoney = getModel(TradeMoney.class, "t");


        TradeMoney db_tradeMoney = dao.findByUpdate(tradeMoney.getNumber(StringPool.PK_COLUMN).intValue());
        final int status = db_tradeMoney.getNumber(FIELD_STATUS).intValue();
        boolean edit = status == SUCCESS_STATUS || status == CONFIRM_STATUS || status == OK_STATUS;
        if (edit) {
            Logger.error("该打款信息已经确认或者已打款，无法修改");
        } else {
            final BigDecimal amount = tradeMoney.getBigDecimal("principal").add(tradeMoney.getBigDecimal("profit"));
            tradeMoney.set(FIELD_AMOUNT, amount);
            tradeMoney.update();
        }
        redirect("/trade/playmoney/" + TypeKit.getInt(db_tradeMoney, "type"));

    }

    /**
     * 执行财务确认打款操作
     * <p/>
     * 财务审核需要先判断下判断电子账户资金是否足够，不足则提示
     */
    @Before(POST.class)
    public void confirm() {

        final AppUser<Model> login = Securitys.getLogin();
        String username = login.getName();
        String data = getPara(PARAM_DATA);
        if (Strings.isNullOrEmpty(data)) {
            renderAjaxFailure("请选择正确的打款纪录");
            return;
        }
        List<String> ids_params = Func.COMMA_SPLITTER.splitToList(data);

        final DateTime now = DateTime.now();
        final Optional<AccountAmountRspDto> merchantAccntAmount = BankService.me.getMerchantAccntAmount(now, now);
        AccountAmountRspDto accountAmountRspDto;
        if (merchantAccntAmount.isPresent()) {
            accountAmountRspDto = merchantAccntAmount.get();
            if (!accountAmountRspDto.isSuccess()) {
                renderAjaxFailure("获取平台账户余额错误，[" + accountAmountRspDto.getRespMsg() + "]");
                return;
            }
        } else {
            renderAjaxFailure("获取平台账户余额错误，请稍后再试!");
            return;
        }

        BigDecimal amount = TradeMoney.dao.countAmount(data);
        if (accountAmountRspDto.getAvailableBalance().compareTo(amount) < 1) {
            renderAjaxFailure("账户可用余额不足，请充值后才可以进行审核");
            return;
        }
        Timestamp confirm_time = new Timestamp(now.getMillis());
        final int param_size = ids_params.size();
        Object[][] params = new Object[param_size][];
        Object[][] record_parmas = new Object[param_size][];
        for (int i = 0; i < param_size; i++) {
            String id = ids_params.get(i);
            Object[] param = new Object[2];
            param[0] = CONFIRM_STATUS;
            param[1] = id;
            params[i] = param;

            Object[] record_param = new Object[5];
            record_param[0] = CommonKit.uuid();
            record_param[1] = id;
            record_param[2] = confirm_time;
            // 1 表示确定
            record_param[3] = 1;
            record_param[4] = username;
            record_parmas[i] = record_param;
        }

        Db.batch(SqlKit.sql("trademoney.updateConfirmOK"), params, 15);
        Db.batch(SqlKit.sql("trademoney.trademoneyaudirecord"), record_parmas, 15);

        renderAjaxSuccess();
    }


    /**
     * 领导审批
     */
    public void approve() {
        final AppUser<Model> login = Securitys.getLogin();
        String username = login.getName();
        String data = getPara(PARAM_DATA);
        if (Strings.isNullOrEmpty(data)) {
            renderAjaxFailure("请选择正确的打款纪录");
            return;
        }
        int type = getParaToInt(0, 0);
        if (type <= 0) {
            renderAjaxFailure("请选择正确的打款纪录");
            return;
        }

        List<TradeMoney> tradeMoneys = dao.findByIds(data, type);
        boolean ok;
        for (TradeMoney tradeMoney : tradeMoneys) {
            if (TypeKit.getStatus(tradeMoney) < CONFIRM_STATUS) {
                renderAjaxFailure("选择的打款结算纪录中，存在财务未确认的打款信息，请核对!");
                return;
            }
        }

        // 退单打款纪录
        List<TradeMoney> tradeMoneysQues = Lists.newArrayList();
        for (TradeMoney tradeMoney : tradeMoneys) {
            switch (type){
                case RAISED_SUCCESS_TYPE:
                case TRANSFER_TYPE:
                case CANCEL_TYPE:
                case PAY_FAIL_TYPE:
                    tradeMoneysQues.add(tradeMoney);
                    break;
            }
            tradeMoney.set(FIELD_STATUS, OK_STATUS);

            ok = tradeMoney.update();
            if (ok) {
                TradeMoneyRecord tradeMoneyRecord = new TradeMoneyRecord();
                tradeMoneyRecord.set(StringPool.PK_COLUMN, CommonKit.uuid());
                tradeMoneyRecord.set("trade_money", TypeKit.getInt(tradeMoney, StringPool.PK_COLUMN));
                tradeMoneyRecord.set("audit_time", DateTime.now());

                // 2 表示批准
                tradeMoneyRecord.set("auditer", 2);
                tradeMoneyRecord.set("audit_name", username);
                tradeMoneyRecord.save();
            }
        }
        if (!Lang.isEmpty(tradeMoneysQues)) {

            switch (type) {
                case CANCEL_TYPE:
                    new InstantPayJob(tradeMoneysQues, CANCEL_TYPE).now();
                    break;
                case TRANSFER_TYPE:
                    new InstantPayJob(tradeMoneysQues, TRANSFER_TYPE).now();
                    break;
                case RAISED_SUCCESS_TYPE:
                    new InstantPayJob(tradeMoneysQues, RAISED_SUCCESS_TYPE).now();
                    break;
                case PAY_FAIL_TYPE:
                    new InstantPayJob(tradeMoneysQues, PAY_FAIL_TYPE).now();
                    break;
            }
        }

        renderAjaxSuccess();
    }

}